// Global variables for the reservation page.
var startDay;
var prevStartDay;
var endDay;
var prevEndDay;
// a copy of the calendar days loaded so far.
var globalCalendarDays;
// use to make the previous cal day as booked.
var isPrevCalDayBooked;
var numberOfGuests = null;
var monthNames = [ "January", "February", "March", "April", "May", "June",
		"July", "August", "September", "October", "November", "December" ];
var dayNames = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
		"Saturday", "Sunday" ];
var MONTH_VERTICAL_PREFIX = "monthVertical_";

/**
 * Printing the entire calendar.
 */
var printEntireCalendar = function(days) {
	var initialDay = parseDay(days[0].date.id);
	var initialMonth = parseMonth(days[0].date.id);

	for ( var day in days) {
		// Print the div to the new months sibling to the left. This is the last
		// day of the initial month.
		printDayDiv("#calendarDiv", days[day], isWorthToPrintVerticalMonth(
				days[day], initialDay, initialMonth));
	}
	
	// If there is a date anchor, then set the focus on it.
	var anchorId = getUrlParameterByName('anchor');
	if(anchorId != null){
		var top = document.getElementById(anchorId).offsetTop; 
	    window.scrollTo(0, top);
	}
};

/**
 * Retrieve the url query param's value
 * @param name The param name to query.
 * @returns
 */
function getUrlParameterByName(name) {
    var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
    return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

var isWorthToPrintVerticalMonth = function(day, initialDay, initialMonth) {
	// This day determines if it's still worthwhile to print the vertical
	// monthname.
	var DAY_THRESHOLD = 21;

	if (parseMonth(day.date.id) == (initialMonth + 1)
			&& parseDay(day.date.id) == 1 && initialDay <= DAY_THRESHOLD)
		return true;
	else
		return false;
};

var printDayDiv = function(containerDivId, calDay, isWorthToPrintVerticalMonth) {

	jQuery('<div/>', {
		id : calDay.date.id,
		class : 'divDay divDayText',
		text : calDay.date.dayOfMonth
	}).appendTo(containerDivId);

	// Add a calendar day div.
	if (calDay.date.isToday == true) {
		jQuery('<div/>', {
			id : calDay.date.id + "_today",
			class : 'calDayToday',
			text : "Today"
		}).appendTo("#" + calDay.date.id);
	}

	// Add the left border for th first div in a row.
	if (calDay.date.dayOfWeek == 1)
		$('#' + calDay.date.id).addClass('divDayFirst');

	// By default assume this is an available calendar day.
	$('#' + calDay.date.id).addClass('divDayAvailable');

	// Color the reservations. Expect max 2 reservations per day that overlap
	for (var i = 0; i < calDay.reservationList.length; i++) {
		// TODO check if this date is more in the future than....
		$('#' + calDay.date.id).addClass('divDayBooked');
		$('#' + calDay.date.id).removeClass('divDayAvailable');

		// There is a reservation. So add css class.
		if (calDay.reservationList.length > 1) {
			$('#' + calDay.date.id).attr("title", calDay.nameOfTenant + " ");			
			var prefix = $('#' + calDay.date.id).attr("title");

			resStateAnte = calDay.reservationList[0].reservationState;
			resStatePost = calDay.reservationList[1].reservationState;
			if (resStateAnte == resStatePost && resStateAnte == 'SETTLED')
				$('#' + calDay.date.id).addClass(
						'divEndDayOfResSettledVsSettled');
			else if (resStateAnte == resStatePost && resStateAnte != 'SETTLED')
				$('#' + calDay.date.id).addClass(
						'divEndDayOfResInProcessingVsInProcessing');
			else if (resStateAnte != resStatePost && resStateAnte == 'SETTLED')
				$('#' + calDay.date.id).addClass(
						'divEndDayOfResSettledVsInProcessing');
			else if (resStateAnte != resStatePost && resStatePost == 'SETTLED')
				$('#' + calDay.date.id).addClass(
						'divEndDayOfResInProcessingVsSettled');
			else if (resStateAnte != resStatePost && resStateAnte != 'SETTLED'
					&& resStatePost != 'SETTLED')
				$('#' + calDay.date.id).addClass(
						'divEndDayOfResInProcessingVsInProcessing');
		} else {
			$('#' + calDay.date.id).attr("title", calDay.nameOfTenant + " ");
			var prefix = $('#' + calDay.date.id).attr("title");
			
			if (calDay.reservationList[i].reservationStart == calDay.date.id) {
				if (calDay.reservationList[i].reservationState == "SETTLED"){
					$('#' + calDay.date.id).addClass('divFirstDayOfResSettled');
					$('#' + calDay.date.id).attr("title", prefix + " - Bestätigte Buchung.");
				}
				else{
					$('#' + calDay.date.id).addClass(
							'divFirstDayOfResInProcessing');
					$('#' + calDay.date.id).attr("title", prefix + " - Buchung noch nicht bestätigt.");
				}
			} else if (calDay.reservationList[i].reservationEnd == calDay.date.id) {
				if (calDay.reservationList[i].reservationState == "SETTLED"){
					$('#' + calDay.date.id).addClass('divEndDayOfResSettled');
					$('#' + calDay.date.id).attr("title", prefix + " - Bestätigte Buchung.");
				}
				else{
					$('#' + calDay.date.id).addClass(
							'divEndDayOfResInProcessing');
					$('#' + calDay.date.id).attr("title", prefix + " - Buchung noch nicht bestätigt.");
				}
			} else {
				if (calDay.reservationList[i].reservationState == "SETTLED"){
					$('#' + calDay.date.id).addClass('divDaySettled');
					$('#' + calDay.date.id).attr("title", prefix + " - Bestätigte Buchung.");
				}
				else{
					$('#' + calDay.date.id).addClass('divDayInProcessing');
					$('#' + calDay.date.id).attr("title", prefix + " - Buchung noch nicht bestätigt.");
				}
			}
		}
	}

	// Break the line.
	if (calDay.date.dayOfWeek == 7)
		$(containerDivId).append("<div/>");

	// Add the week day
	jQuery('<div/>', {
		class : 'divWeekDayText',
		text : dayNames[calDay.date.dayOfWeek - 1]
	}).appendTo('#' + calDay.date.id);

	// Add the month to to every day, but hide it except for the first day of
	// the month

	jQuery(
			'<div/>',
			{
				class : 'divMonthText divMonthTextHide',
				text : monthNames[calDay.date.monthOfYear - 1] + " '"
						+ calDay.date.year.toString().substring(2, 4)
			}).appendTo('#' + calDay.date.id);

	// Also add the month to the right hand side of the very last calendar day
	// of the row
	if (calDay.date.dayOfMonth <= 7 && calDay.date.dayOfWeek == 7) {
		var dayElement = $('#' + calDay.date.id);
		printVerticalMonth(dayElement, calDay.date.monthOfYear, false);
	}

	if (isWorthToPrintVerticalMonth) {
		var dayElement = $('#' + calDay.date.id).prev().prev();
		printVerticalMonth(dayElement, calDay.date.monthOfYear - 1, true);
	}

};

// Print the month to the side of the calendar.
var printVerticalMonth = function(elementToAppendTo, monthNumber,
		isInitialMonth) {
	var divId = MONTH_VERTICAL_PREFIX + monthNumber;
	var monthName = monthNames[monthNumber - 1];
	var MAX_CHARS = 7;
	var TRAILS = "...";
	var NUM_OF_TRAILS = TRAILS.length;

	if (isInitialMonth) {
		//$('#' + divId).addClass('monthVerticalCutOff');

		if (monthName.length > MAX_CHARS + NUM_OF_TRAILS) {
			var trimmedMonth = monthName.substring(0, MAX_CHARS) + TRAILS;
			$("#" + divId).html(trimmedMonth);
		}
	} else {
		elementToAppendTo.after(jQuery('<div/>', {
			id : divId,
			class : 'monthVertical',
			text : monthName
		}));
	}
};

// Load the print function/calendar initially
$.printInitialCalendar = function(loadingBlock) {
	if (loadingBlock == null)
		loadingBlock = 1;

	requestUrl = MAIN_REST_URL + "calendar/" + loadingBlock;

	$.ajax({
		url : requestUrl,
		dataType : 'json',
		success : function(calendarDays) {
			// add the response to the global variable
			if (globalCalendarDays == null)
				globalCalendarDays = calendarDays;
			else
				globalCalendarDays = globalCalendarDays.concat(calendarDays);

			printEntireCalendar(calendarDays);
		},
		context : document.body
	});
};

// Register AJAX transaction listeners.
$(document).ajaxSend(function(event, request, settings) {
	//$("#loadingDiv").css("color", "#efefef");
	$("#loadingDiv").html("Lade Kalender ...");
});
$(document).ajaxError(function(event, request, settings) {
	$("#loadingDiv").css("color", "red");
	$("#loadingDiv").html("Konnte keine Kalenderdaten vom Server laden.");
});
$(document)
		.ajaxSuccess(
				function(event, request, settings) {
					$("#loadingDiv").css("color", "inherit");
					$("#loadingDiv")
							.html(
									"Möchtest du mehr verfügbare Daten sehen? Einfach mit der Maus scrollen.");
				});

// Function to mark the date in between the days.
// Refuse to mark blocked dates.
var markIntervalAsSelected = function(startDayString, endDayString) {
	var startDay = new Date(startDayString);
	var endDay = new Date(endDayString);

	var indexDate = new Date(startDayString);
	while (indexDate <= endDay) {
		strDivIndex = indexDate.getFullYear() + "-"
				+ ('0' + (indexDate.getMonth() + 1)).slice(-2) + "-"
				+ ('0' + indexDate.getDate()).slice(-2);
		indexDate.setDate(indexDate.getDate() + 1);
		$("#" + strDivIndex).addClass("ui-selected");
	}
};

// Remove selectability of invalid dates
var removeSelectabilityOfInvalidDates = function(selectedDate) {
	// Loop from startDate to selectedDate.
	// Use a temporary CLASS to disable the calendar days -->divDayTmpDisabled
	var isAvailablePeriod = false;
	for ( var earlierDay in globalCalendarDays) {
		var iDate = globalCalendarDays[earlierDay];
		if (!isAvailablePeriod) {
			if (iDate.date.id == selectedDate) {
				isAvailablePeriod = true;
				continue;
			}
			$("#" + iDate.date.id).addClass("divDayTmpDisabled");
		} else {
			if (iDate.reservationList.length != 0) {
				isAvailablePeriod = false;
				$("#" + iDate.date.id).addClass("divDayTmpDisabled");
			}
		}
	}
};

var addSelectabilityOfAllDates = function() {
	for ( var earlierDay in globalCalendarDays) {
		$("#" + globalCalendarDays[earlierDay].date.id).removeClass(
				"divDayTmpDisabled");
	}
};

// Check if the subsequent day is a blocked date.
var isValidStartDate = function(startDateString) {

	var isValidStartDate = true;
	var isNextDay = false;
	for (var i = 0; i < globalCalendarDays.length; i++) {
		var iDate = globalCalendarDays[i];

		if (isNextDay && iDate.reservationList.length > 0) {
			isValidStartDate = false;
			break;
		} else if (isNextDay) {
			break;
		}

		if (iDate.dateString == startDateString)
			isNextDay = true;
	}
	return isValidStartDate;
};

// Check if the selected end date is valid and not on or after a booked date.
var isValidEndDate = function(startDateString, endDateString) {
	var startDate = new Date(startDateString);
	var endDate = new Date(endDateString);

	// var indexDate = new Date(startDateString);
	var isValidEndDate = true;
	// for(var iDay in globalCalendarDays){
	for (var i = 0; i < globalCalendarDays.length; i++) {
		var iDate = globalCalendarDays[i];
		var indexDate = new Date(iDate.dateString);
		if (indexDate > startDate) {
			if (indexDate > endDate)
				break;
			if (iDate.reservationList.length > 0) {
				return false;
			}
		}
	}
	// There has not found a reservation. Thus, any selectable end date is fine.
	return isValidEndDate;
};

// Reestablish the selectability of earlier dates.
var reestablishSelectabilityOfEarlierDates = function() {
	// Loop through all calendar days.
};

var countDays = function(startDayString, endDayString) {
	var startDay = new Date(startDayString);
	var endDay = new Date(endDayString);
	var indexDate = new Date(startDayString);
	var count = 0;
	while (indexDate <= endDay) {
		indexDate.setDate(indexDate.getDate() + 1);
		count++;
	}
	return count;
};

var setAdditionalCurrencies = function(amount) {
	requestUrl = MAIN_REST_URL + "general/currency/" + Math.round(amount);
	$("#resInfoTdOtherInfo").empty();
	$("#resInfoTdLoading").html("lade lokale Währung");
	$("#resInfoTdLoading").addClass("animateFlicker");
	$("#resInfoTdLoading").removeClass("deactivated");

	$.ajax(
			{
				url : requestUrl,
				dataType : 'json',
				success : function(response) {
					for ( var cur in response) {
						$("#resInfoTdOtherInfo").append(
								"circa " + response[cur].targetCurrency + " "
										+ response[cur].amount);
					}
					$("#resInfoTdLoading").html("");
					$("#resInfoTdLoading").removeClass("animateFlicker");
				},
				context : document.body
			}).fail(function() {
		$("#resInfoTdLoading").removeClass("animateFlicker");
		$("#resInfoTdLoading").html("Failed to provide other currencies.");
		$("#resInfoTdLoading").addClass("deactivated");
	});

};

var populateCosts = function(numberofGuests, startDayString, endDayString) {
	requestUrl = MAIN_REST_URL + "reservation/costs/" + numberofGuests
			+ "/" + startDayString + "/" + endDayString;

	$.ajax({
		url : requestUrl,
		dataType : 'json',
		success : function(response) {
			$("#resInfoTdStartDate").html(prettyPrintDate(response.startDate));
			$("#resInfoTdEndDate").html(prettyPrintDate(response.endDate));
			$("#resInfoTdVacCosts").html(
					parseFloat(response.reservationCosts).toFixed(2));
			$("#resInfoTdCleaningFee").html(
					parseFloat(response.cleaningFee).toFixed(2));
//			$("#resInfoTdVatPercentage").html(
//					"Vermietsteuer " + response.vatPercentage * 100 + "%");
			$("#resInfoTdVat").html(parseFloat(response.vatAmount).toFixed(2) + " ("+ response.vatPercentage * 100 + "%)");
			$("#resInfoTdTotalCosts").html(
					response.currency + " "
							+ parseFloat(response.totalCosts).toFixed(2));
			$("#resInfoTdSeasonFactor").html(
					parseFloat(response.seasonFactor).toFixed(2));

			$('#resInfoTdGuests').empty();
			jQuery('<a/>', {
				href : 'javascript:showGuestDialog()',
				id : 'resInfoGuestsLink',
				text : response.numberOfGuests + " (wechseln)"
			}).appendTo("#resInfoTdGuests");
			setAdditionalCurrencies(response.totalCosts);

			var RES_FORM = "#reservationForm\\:";
			// Set the hidden fields for the form registration.
			var startDateElement = $(RES_FORM + 'startDate');
			startDateElement.val(shortPrintDate(response.startDate));

			var endDateElement = $(RES_FORM + 'endDate');
			endDateElement.val(shortPrintDate(response.endDate));

			var numberOfGuestsElement = $('input[id$=numberOfGuests]');
			numberOfGuestsElement.val(response.numberOfGuests);
		},
		context : document.body
	});
};

// Print for view.
var prettyPrintDate = function(dateToFormat) {
	return monthNames[dateToFormat.monthOfYear - 1] + " "
			+ dateToFormat.dayOfMonth + "" + ", "
			+ dateToFormat.year.toString();
};

// Print for IDs and others.
var shortPrintDate = function(dateToFormat) {
	return dateToFormat.year + "-" + dateToFormat.monthOfYear + "-"
			+ dateToFormat.dayOfMonth;
};

var showGuestDialog = function() {
	var spinner = $("#spinner").spinner({
		min : 2,
		max : 6
	});

	$("#dialog-confirm").dialog({
		resizable : false,
		height : 'auto',
		width : 450,
		modal : true,
		buttons : {
			"ok" : function() {
				numberOfGuests = spinner.spinner("value");
				populateCosts(numberOfGuests, startDay, endDay);
				$(this).dialog("close");
			},
			Cancel : function() {
				$(this).dialog("close");
			}
		}
	});
};

var parseMonth = function(dateString) {
	var month = dateString.substring(5, 7);
	return parseInt(month);
};

var parseDay = function(dateString) {
	var day = dateString.substring(8, 10);
	return parseInt(day);
};

var positionResInfoDiv = function(selectedStartDay, selectedEndDays) {
	var div = "resInfoDiv";
	var parentPosLeftOfCore = $('#contentCore').offset().left;
	var divPosTop = $('#' + selectedStartDay).position().top;
	$("#" + div).css({
		'display' : 'block',
		'top' : Math.round(divPosTop),
		'left' : Math.round(parentPosLeftOfCore) - 300
	});
	var sumHeight = Math.round(divPosTop + $("#resInfoDiv").height());

	// Adjust if sum height exeeds windows size
	var diff = $(window).height() - sumHeight;
	if (diff < 0)
		$("#" + div).css({
			'top' : Math.round(divPosTop - Math.abs(diff) - 20)
		});

	$("#" + div).show();
};


// When the document is loaded, start loading the block.
var loadingBlockIndex = 1;

$(document)
		.ready(
				function() {
					var selectedStartDay;
					var selectedEndDay;
					var MAX_NUM_OF_GUESTS = 6;
					var MAX_NUM_OF_EXTRA_GUESTS = 2;
					// Load the data
					$.printInitialCalendar(loadingBlockIndex);

					// Employ a delegate for future created tag elements and
					// toggle the css.
					$("#calendarDiv").on(
							'mouseenter',
							'.divDay',
							function() {
								// $(this).css({'background-color': '#EFEFEF',
								// 'border-radius': '0px 0px 0px 0px',
								// 'opacity': '1'});
								$(this).css({
									'background-color' : '#EFEFEF',
									'border-radius' : '0px 0px 0px 0px'
								});
								$(this).find('.divWeekDayText').addClass(
										'divWeekDayTextGlow');
								$(this).find('.divMonthText').removeClass(
										'divMonthTextHide');
								// highlight the vertical month
								month = MONTH_VERTICAL_PREFIX
										+ parseMonth(this.id);
								$('#' + month).addClass(
										'monthVerticalHighlight');
							}).on(
							'mouseleave',
							'.divDay',
							function() {
								$(this).css({
									'background-color' : '',
									'border-radius' : '0px'
								});
								$(this).find('.divWeekDayText').removeClass(
										'divWeekDayTextGlow');
								$(this).find('.divMonthText').addClass(
										'divMonthTextHide');
								// remove the highlighting of the month
								month = MONTH_VERTICAL_PREFIX
										+ parseMonth(this.id);
								$('#' + month).removeClass(
										'monthVerticalHighlight');
							});

					// Lazy data loading on scroll
					$(window).scroll(
									function() {
										
										
										var scrollAndHeight = $(window).scrollTop() + $(window).height();									
										
										
										if (scrollAndHeight == $(document).height()) {
											loadingBlockIndex = loadingBlockIndex + 1;
											$.printInitialCalendar(loadingBlockIndex);
											//alert(scrollAndHeight + ", " + $(document).height() );
										}
										// TODO Caution, must also load data if
										// document height is smaller than
										// window height.
										if ($(window).height() > $(document).height()) {
											loadingBlockIndex = loadingBlockIndex + 1;
											$.printInitialCalendar(loadingBlockIndex);
											alert(scrollAndHeight + ", " + $(document).height() );
										}										
									});

					// Make divs selectable.
					$(function() {
						$("#calendarDiv").selectable();
					});

					// Invoke the a function when selected
					$("#calendarDiv")
							.selectable(
									{
										// delay: 250,
										filter : ".divDayAvailable",
										selecting : function(event, ui) {
											// TODO-1 Make sure there is no
											// reservation in between. Deselect
											// if necessary.

											// TODO-2
										},
										selected : function(event, ui) {
											if (selectedStartDay == null) {
												// Actions, when a first date
												// hast been selected.
												selectedStartDay = ui.selected.id;
												// Check if calendar day is
												// allowed.
												if (isValidStartDate(selectedStartDay)) {
													// Clean the start and end
													// title of previous
													// selections.
													$("#" + startDay).attr(
															'title', '');
													$("#" + endDay).attr(
															'title', '');

													// Mark selected start date.

													$("#" + selectedStartDay)
															.attr('title',
																	'This is the starting day of your reservation. Now, select an end date.');
													$(document).tooltip({
														track : true
													});
													// Hide the reservation info
													// div.
													$("#resInfoDiv").hide();
													// Make cal dates before
													// this date not selectable.
													removeSelectabilityOfInvalidDates(selectedStartDay);
												} else {
													// Delete the selection
													$("#" + selectedStartDay)
															.removeClass(
																	'ui-selected');
													selectedStartDay = null;
													$(
															"#dateToCloseToBookedDialog")
															.dialog({
																modal : true
															});
												}
											} else if (selectedStartDay != null
													&& selectedEndDay == null) {
												// Actions, when an end date has
												// been selected.
												selectedEndDay = ui.selected.id;
												// Check if, calendar day
												// allowed to be selected.
												if (isValidEndDate(
														selectedStartDay,
														selectedEndDay)) {

													var tmpStartDay = new Date(
															selectedStartDay);
													var tmpEndDay = new Date(
															selectedEndDay);

													if (tmpStartDay >= tmpEndDay) {
														$("#dateIssueDialog")
																.dialog(
																		{
																			modal : true
																		});
														$("#" + selectedEndDay)
																.removeClass(
																		'ui-selected');
														$(
																"#"
																		+ selectedStartDay)
																.addClass(
																		'ui-selected');
														selectedEndDay = null;
														return;
													}

													markIntervalAsSelected(
															selectedStartDay,
															selectedEndDay);
													$("#" + selectedStartDay)
															.attr('title',
																	'This is the starting day of your reservation.');
													// Save in global variables.
													startDay = selectedStartDay;
													endDay = selectedEndDay;
													// Ask for the number of guest, if not yet provided.
													if (numberOfGuests == null
															|| numberOfGuests == 0
															|| numberOfGuests > MAX_NUM_OF_GUESTS) {
														showGuestDialog();
													} else {
														populateCosts(
																numberOfGuests,
																startDay,
																endDay);
													}
													$("#" + selectedEndDay)
															.attr('title',
																	'This is the end day of your reservation.');

													var numOfDays = countDays(
															selectedStartDay,
															selectedEndDay);
													var numOfNights = numOfDays - 1;
													$("#resInfoTdDays")
															.html(
																	numOfDays
																			+ "/"
																			+ numOfNights);

													// Position the reservation div.
													positionResInfoDiv(selectedStartDay);
													// Clean up	
													selectedStartDay = null;
													selectedEndDay = null;
													// Remove the "selection-disabled" property from other dates
													addSelectabilityOfAllDates();
												} else {
													selectedEndDay = null;
													$("#dateNotVacantDialog")
															.dialog({
																modal : true
															});
												}
											} else {
												selectedStartDay = null;
											}

										}
									});

				});